/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef IMAGE_KNIFE_C_DECODE_INTERCEPTOR_OH_H
#define IMAGE_KNIFE_C_DECODE_INTERCEPTOR_OH_H

#include <multimedia/image_framework/image/image_source_native.h>
#include "imageknife_task_internal.h"
#include "interceptor.h"
#include "imageknife_request.h"
#include "imageknife_data_napi.h"
#include "hitrace/trace.h"
#include "pixelmap_utils.h"

namespace ImageKnifePro {
class DecodeInterceptorDefault : public DecodeInterceptor {
public:
    DecodeInterceptorDefault()
    {
        name = "Default DecodeInterceptor";
    }

    bool Resolve(std::shared_ptr<ImageKnifeTask> task) override
    {
        bool result = false;
        static std::atomic<int> idx =  1;
        int traceId = idx;
        idx++;

        if (task->GetImageBufferFormat() == ImageFormat::UNKNOWN) {
            return false;
        }
        if (task->product.imageBuffer == nullptr) {
            task->EchoError("Empty ImageBuffer");
            return false;
        }

        auto taskInternal = std::dynamic_pointer_cast<ImageKnifeTaskInternal>(task);
        IMAGE_KNIFE_CHECK_RETURN(taskInternal == nullptr, false);
        OH_HiTrace_StartAsyncTrace (name.c_str(), traceId);
        if (taskInternal->IsFrameDecodeMode()) {
            IMAGE_KNIFE_LOG(LOG_DEBUG, "%{public}s DecodeFrame : %{public}d",
                taskInternal->GetTaskInfo().c_str(), taskInternal->GetDecodeFrameIndex());
            result = DecodeFrame(taskInternal);
        } else {
            result = Decode(taskInternal);
        }
        OH_HiTrace_FinishAsyncTrace(name.c_str(), traceId);

        return result;
    }
private:
    struct DecodeArgs {
        OH_DecodingOptions *decodeOption = nullptr;
        ~DecodeArgs()
        {
            if (decodeOption != nullptr) {
                OH_DecodingOptions_Release(decodeOption);
            }
        }
    };

    bool DecodeFrame(std::shared_ptr<ImageKnifeTaskInternal> task);

    bool Decode(std::shared_ptr<ImageKnifeTaskInternal> task)
    {
        OH_ImageSourceNative *source = task->GetImageSourceNative();
        if (source == nullptr) {
            task->EchoError("Get ImageSourceNative Failed");
            return false;
        }

        uint32_t frameCount = task->GetImageSourceFrameCount();
        if (frameCount == 0) {
            task->EchoError("Invalid Frame Count");
            return false;
        }

        DecodeArgs args;
        if (!ConfigDecodeOption(args, task)) {
            return false;
        }

        if (frameCount > 1) {
            int *delayList = new int[frameCount];
            // 获取每帧时间信息
            Image_ErrorCode imgErrorCode = OH_ImageSourceNative_GetDelayTimeList(source, delayList, frameCount);
            if (imgErrorCode != IMAGE_SUCCESS) {
                task->EchoError("Get DelayTimeList Failed, error code: " + std::to_string(imgErrorCode));
                delete [] delayList;
                return false;
            }

            OH_PixelmapNative **pixelmapList = new OH_PixelmapNative* [frameCount];
            imgErrorCode = OH_ImageSourceNative_CreatePixelmapList(source, args.decodeOption, pixelmapList, frameCount);
            if (imgErrorCode != IMAGE_SUCCESS) {
                task->EchoError("Create Pixelmap List Failed, error code: " + std::to_string(imgErrorCode));
                delete [] pixelmapList;
                return false;
            }
            task->product.imageData = std::make_shared<ImageData>(pixelmapList, delayList, frameCount);
        } else {
            OH_PixelmapNative *pixelmap = nullptr;
            Image_ErrorCode imgErrorCode = OH_ImageSourceNative_CreatePixelmap(source, args.decodeOption, &pixelmap);
            if (imgErrorCode != IMAGE_SUCCESS) {
                task->EchoError("Create Pixelmap Failed, error code: " + std::to_string(imgErrorCode));
                return false;
            }
            task->product.imageData = std::make_shared<ImageData>(pixelmap);
        }

        Orientate(task, source);
        return true;
    }

    bool ConfigDecodeOption(DecodeArgs &args, std::shared_ptr<ImageKnifeTaskInternal> &task)
    {
        // 创建解码Option
        Image_ErrorCode imgErrorCode = OH_DecodingOptions_Create(&args.decodeOption);
        if (imgErrorCode != IMAGE_SUCCESS) {
            task->EchoError("Create Decode Option Failed, error code: " + std::to_string(imgErrorCode));
            return false;
        }
        // 设置期望解码尺寸
        Image_Size imageSize = task->GetDesiredImageSize();
        if (imageSize.width != 0 && imageSize.height != 0) {
            OH_DecodingOptions_SetDesiredSize(args.decodeOption, &imageSize);
        }

        // 设置指定解码帧index
        if (task->IsFrameDecodeMode()) {
            OH_DecodingOptions_SetIndex(args.decodeOption, task->GetDecodeFrameIndex());
        }
        return true;
    }

    void Orientate(std::shared_ptr<ImageKnifeTask> task, OH_ImageSourceNative *source)
    {
        if (task->GetImageRequestType() != ImageRequestType::MAIN_SRC) {
            return;
        }

        auto request = task->GetImageKnifeRequest();
        IMAGE_KNIFE_CHECK(request == nullptr);
        auto option = request->GetImageKnifeOption();
        IMAGE_KNIFE_CHECK(option == nullptr);

        if (option->orientation != Orientation::AUTO) {
            return;
        }

        std::string keyStr = "Orientation";
        Image_String key = {.data = (char *)keyStr.c_str(), .size = keyStr.length()};
        Image_String value = {.data = nullptr, .size = 0};
        OH_ImageSourceNative_GetImageProperty(source, &key, &value);
        // Image_String 返回的data没有包含尾0
        std::string valueStr(value.data, value.size);
        PixelmapUtils::Orientate(task->product.imageData, valueStr);
        // 按接口说明需要释放分配的内存
        free(value.data);
    }
};
};

#endif // IMAGE_KNIFE_C_DECODE_INTERCEPTOR_OH_H
